import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
import javax.swing.filechooser.*;

interface Rule {
   //public void apply();
   public int apply(final int state, final int[] neighbors);
   public int getStateCount();
}
final class Rule2D implements Rule {
   public static final Rule2D LIFE=new Rule2D("23", "3", 0); //Life Rule
   public static final Rule2D LOGIC=new Rule2D("", "2", 0); //Logic Rule
   public static final Rule2D BRAIN=new Rule2D("", "2", 1); //Brain Rule
   public static final Rule2D BRAIN6=new Rule2D("6", "246", 1); //Brain 6
   public static final Rule2D BOMBERS=new Rule2D("345", "24", 23); //Bombers
   public static final Rule2D FLAKES=new Rule2D("012345678", "3", 0); //Flakes
   public static final Rule2D FADERS=new Rule2D("2", "2", 23); //Faders

   public static final int DEAD=0;
   public static final int LIVE=1;
   private final java.util.Set<Integer> survival=new TreeSet<Integer>();
   private final java.util.Set<Integer> birth=new TreeSet<Integer>();
   private int ghostStates;

   /*
   //can't accept numbers start with zero.
   public Rule2D(int s, int b, int g) {
      while(s>0) {
         survival.add(s%10);
         s/=10;
      }
      while(b>0) {
         birth.add(b%10);
         b/=10;
      }
      ghostStates=g;
   }
   */
   public Rule2D(String s, String b, int g) {
      init(s, b, g);
   }
   public Rule2D(String ruleStr) {
      if(!isValidStr(ruleStr)) {
         throw new IllegalArgumentException();
      }
      final int firstSlashIndex=ruleStr.indexOf("/");
      final String sStr=ruleStr.substring(0, firstSlashIndex);
      final int secondSlashIndex=ruleStr.indexOf("/", firstSlashIndex+1);
      final String bStr=ruleStr.substring(firstSlashIndex+1, secondSlashIndex);
      final String gStr=ruleStr.substring(secondSlashIndex+1, ruleStr.length());
      init(sStr, bStr, gStr.equals("")?0:Integer.parseInt(gStr));
   }
   private final void init(String s, String b, int g) {
      for(int i=0; i<s.length(); i++) {
         survival.add(Integer.parseInt(String.valueOf(s.charAt(i))));
      }
      for(int i=0; i<b.length(); i++) {
         birth.add(Integer.parseInt(String.valueOf(b.charAt(i))));
      }
      ghostStates=g;
   }
   public static boolean isValidStr(String src) {
      if(src.matches("\\d*+/\\d*+/\\d*+")) {
         return true;
      } else {
         return false;
      }
     
   }
   private static int countNeighbors(int[] neighbors, int state) {
      int count=0;
      for(int i=0; i<neighbors.length; i++) {
         if(neighbors[i]==state) count++;
      }
      return count;
   }
   public int getStateCount() {
      return 2+ghostStates; //(DEAD+LIVE)+ghostStates
   }
   public int apply(final int state, final int[] neighbors) {
      int n=countNeighbors(neighbors, LIVE);
      if(state==DEAD) {
         for(int b: birth) {
            if(n==b) return LIVE;
         }
         return DEAD;
      } else if(state==LIVE) {
         for(int s: survival) {
            if(n==s) return LIVE;
         }
         return (state+1)%getStateCount();
      } else {
         return (state+1)%getStateCount();
      }
   }
   public String toString() {
      StringBuffer sb=new StringBuffer();
      for(int s: survival) {
         sb.append(s);
      }
      sb.append("/");
      for(int b: birth) {
         sb.append(b);
      }
      sb.append("/");
      sb.append(ghostStates);
      return sb.toString();
   }
   @Override public boolean equals(Object o) {
      if(o==null) return false;
      if(o.getClass()!=this.getClass()) return false;
      Rule2D that=(Rule2D)o;
      if(!that.survival.equals(this.survival)) return false;
      if(!that.birth.equals(this.birth)) return false;
      if(that.ghostStates!=this.ghostStates) return false;
      //if(!that.toString().equals(this.toString())) return false;
      //System.out.printf("%s == %s", that, this);
      return true;
   }
}
